package com.hhq.core;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.TreeMap;

import com.hhq.annotation.ViewFun;
import com.hhq.middle.Middle;

public class Controller {

    // url 对应视图函数的 map， {"/user/find", ["get", "findUser", "com.hhq.Views"]}
    public static Map<String, String[]> map = new TreeMap<>();

    // 中间件 分别在前、后运行
    private static Middle[] befores;
    private static Middle[] afters;

    // 下面是请求路径和视图函数的对应关系
    // 第一个参数是路径，第二个参数是Views类当中的方法
    static {
        try {
            // 加载视图函数相关
            for (String pack : Config.VIEW_PATH) {
                Map<String, String[]> tmp = getViewAnnotation(pack);
                map.putAll(tmp);
            }
            // 加载中间件
            befores = new Middle[Config.befores.length];
            int i=0;
            for(String pack : Config.befores){
                Class<?> clazz = Class.forName(pack);
                befores[i++] = (Middle) clazz.newInstance();
            }
            afters = new Middle[Config.afters.length];
            i=0;
            for(String pack : Config.afters){
                Class<?> clazz = Class.forName(pack);
                afters[i++] = (Middle) clazz.newInstance();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void controller(Req req, Res res) {
        try {
            System.out.println("request url is: " + req.url);
            for(Middle bef : befores){
                if (bef == null){
                    System.out.println("定义的 befores 中间件错误，请查看配置文件！");
                }
                if( ! bef.deal(req, res)){  // 如果中间件返回false，直接结束返回
                    return;
                }
            }
            // 看看map中是否有对应url的方法
            if (map.containsKey(req.url)) {
                String[] mm = map.get(req.url);
                // 请求方法匹配 例如GET
                if (mm[0].equals(req.method)) {
                    Class<?> clazz = Class.forName(mm[2]);
                    Method method = clazz.getMethod(mm[1], Req.class, Res.class);
                    // invoke调用  this， 参数123,。。
                    method.invoke(clazz.newInstance(), req, res);
                } else {
                    res.code = 415;
                    res.desc = "method error";
                    res.body = "视图类的http请求方法错误：" + mm[0] + ", " + mm[1];
                    System.out.println("视图类的http请求方法错误：" + mm[0] + ", " + mm[1]);
                    return;
                }
            } else {
                // 不存在则按照静态文件处理
                static_file(req, res);
            }
            for(Middle aft : afters){
                if (aft == null){
                    System.out.println("定义的after中间件错误，请查看配置文件！");
                }
                if( ! aft.deal(req, res)){  // 如果中间件返回false，直接结束返回
                    return;
                }
            }
        } catch (NoSuchMethodError nse) {
            System.out.println("视图类中找不到这个方法：" + map.get(req.url));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 获取视图的注解信息，例如path、http方法、类名等
    // 返回 {"/user/find", ["get", "findUser", "com.hhq.Views"]} 
    private static Map<String, String[]> getViewAnnotation(String viewClassName) throws Exception {
        Map<String, String[]> map = new TreeMap<>();
        final Class<?> clazz = Class.forName(viewClassName);   // 获取类
        final Method[] allMethods = clazz.getDeclaredMethods();  // 获取所有方法
        // 遍历方法
        for (int i = 0; i < allMethods.length; i++) {
            //如果有ViewFun的注解
            if (allMethods[i].isAnnotationPresent(ViewFun.class)) {   
                final ViewFun methodAnno = allMethods[i].getAnnotation(ViewFun.class);
                String path = methodAnno.path(); // /user
                String method = methodAnno.method(); // get -》toUpperCase  GET
                String methodName = allMethods[i].getName();
                // insert
                // {"/user/find", ["get", "findUser", "com.hhq.Views"]} 
                map.put(path, new String[] { method.toUpperCase(), methodName, viewClassName });
            }
        }
        return map;
    }

    // 处理静态文件
    private static void static_file(Req req, Res res) {
        String path = Config.STATIC_PATH + req.url;
        File file = new File(path);
        if (file.exists() && file.isFile()) {
            FileInputStream fileInputStream;
            try {
                fileInputStream = new FileInputStream(file);
                byte[] buf = new byte[1024*4];
                int len;
                ByteArrayOutputStream bao = new ByteArrayOutputStream();
                len = fileInputStream.read(buf);
                while (len != -1) {
                    bao.write(buf, 0, len);
                    len = fileInputStream.read(buf);
                }
                bao.close();
                res.bboby = bao.toByteArray();
                res.code = 200;
                res.desc = "OK";
                if (path.contains(".")) {  // 设置MIME 类型
                    String[] args = path.split("\\.");
                    String last = args[args.length - 1].toLowerCase();
                    if (Config.mineMaps.containsKey(last)) {
                        res.headers.put("Content-Type", Config.mineMaps.get(last));
                    }
                }
                fileInputStream.close();
            } catch (FileNotFoundException e1) {
                System.out.println("[error]file not found! :" + path);
            } catch (IOException e2) {
                System.out.println("[error] IO error in: " + path);
            }
        } else {
            res.code = 404;
            res.desc = "Not Found";
            res.body = "no such a URL or static file: " + req.url;
        }
    }

}